//./createLingoLibrary configFileLibrary.txt LibraryGenerated.gz
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <math.h>

#include <iostream>
#include <fstream>

#include "zlib.h"

#include "ListE.h"
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define LINGOLENGTH  4
#define LENGTHARRAY  40096
#define CUTOFFFREQ   1
#define ORIGINALFREQ 0
#define CHANGEDIGIT  '?'
#define EUCLIDIAND   1
#define POSITIONL    1
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
struct LingoFreq {

  char  *lingo;
  int    frequency;

  LingoFreq() {
    this->lingo     = NULL;
    this->frequency = 0;
  }

  ~LingoFreq() {
    if (lingo) delete[] lingo;
  }

  struct LingoFreq operator=(const struct LingoFreq &lingoFreq) {

    if (this->lingo) delete[] this->lingo;
    this->lingo = new char[strlen(lingoFreq.lingo) + 1];
    strcpy(this->lingo, lingoFreq.lingo);

    this->frequency = lingoFreq.frequency;

    return *this;

  };

};

#define LINGOFreq struct LingoFreq

struct fileLingoFreq {

    char *name;
    int   lengthLingo;

    fileLingoFreq() {
      name        = NULL;
      lengthLingo = 0;
    };
    ~fileLingoFreq() {
      if (name) delete[] name;
    };

  };

#define FileLingoFreq struct fileLingoFreq

struct SmilesRef {

  char  *smiles;
  char  *ref;

  SmilesRef() {
    this->smiles = NULL;
    this->ref    = NULL;
  }

  ~SmilesRef() {
    if (smiles) delete[] smiles;
    if (ref)    delete[] ref;
  }

  struct SmilesRef operator=(const struct SmilesRef &smilesRef) {

    if (this->smiles) delete[] this->smiles;
    this->smiles = new char[strlen(smilesRef.smiles) + 1];
    strcpy(this->smiles, smilesRef.smiles);

    if (this->ref) delete[] this->ref;
    this->ref = new char[strlen(smilesRef.ref) + 1];
    strcpy(this->ref, smilesRef.ref);

    return *this;

  };

};

#define SMILESRef struct SmilesRef

//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
namespace LingoSpace {

  bool FindLingo(TNode *NodeT, void* ref = NULL) {
    return (!strcmp(((LINGOFreq*)NodeT->Info())->lingo, (char*)ref))?true:false;
  }

  bool FindReference(TNode *NodeT, void* ref = NULL) {
    return (!strcmp(((SMILESRef*)NodeT->Info())->ref, (char*)ref))?true:false;
  }

  bool MajorFreq(TNode *NodeT, void* ref) {
    int FreqA = ((LINGOFreq*)NodeT->Info())->frequency;
    int FreqB = ((LINGOFreq*)((TNode*)ref)->Info())->frequency;
    return (FreqA > FreqB)?true:false;
  }

  bool AlphLingo(TNode *NodeT, void* ref) {
    char *LingoA = ((LINGOFreq*)NodeT->Info())->lingo;
    char *LingoB = ((LINGOFreq*)((TNode*)ref)->Info())->lingo;
    return (strcmp(LingoA, LingoB) > 0)?true:false;
  }

  bool ContainLingoInit(TNode *NodeT, void* ref = NULL) {
    printf("LINGO Compare %s Refe %s\n", (((LINGOFreq*)NodeT->Info())->lingo), (char*)ref);

    return (strstr(((LINGOFreq*)NodeT->Info())->lingo, (char*)ref))?true:false;
  }

  bool ContainLingoEnd(TNode *NodeT, void* ref = NULL) {
    printf("LINGO Compare %s\n", (((LINGOFreq*)NodeT->Info())->lingo));
    return (!strcmp((((LINGOFreq*)NodeT->Info())->lingo + 1), (char*)ref))?true:false;
  }

  int ContainLingoInitS(TNode *NodeT, void* ref = NULL) {
    //printf("LINGO Compare %s Refe %s\n", (((LINGOFreq*)NodeT->Info())->lingo), (char*)ref);
    if (strcmp(((LINGOFreq*)NodeT->Info())->lingo, (char*)ref) < 0) return -1;
    return (strstr(((LINGOFreq*)NodeT->Info())->lingo, (char*)ref))?1:0;
  }

  int ContainLingoEndS(TNode *NodeT, void* ref = NULL) {
    //printf("LINGO Compare %s  Refe %s\n\n", (((LINGOFreq*)NodeT->Info())->lingo + 1), (char*)ref);
    //if (strcmp((((LINGOFreq*)NodeT->Info())->lingo + 1), (char*)ref) < 0) return -1;
    return (!strcmp((((LINGOFreq*)NodeT->Info())->lingo + 1), (char*)ref))?1:0;
  }
};
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void trim(char *stream) {

  int i, j;
  for (i = 0, j = 0; i < strlen(stream); i++)
    if ((stream[i] != '\n') && (stream[i] != '\r') && (stream[i] != ' '))
        stream[j++] = stream[i];
  stream[j] = '\0';

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
char **GetAllFiles(const char *path, int &numberFiles) {

  DIR     *dir = opendir(path);
  struct   dirent *dp;             /* returned from readdir() */
  size_t   filecount = 0;          /* number of entries in directory */
  size_t   i = 0;
  char   **files;

  if (dir == NULL) return NULL;    /* opendir() failed */

  /* Pass 1: Count number of files and subdirectories */
  while ((dp = readdir(dir)) != NULL) filecount++;

  numberFiles = filecount;

  /* Allocate space for the result */
  files = (char **)malloc(filecount * sizeof(*files));
  if (files == NULL) return NULL;  /* malloc failed */

  /* Pass 2: Collect all filenames */
  rewinddir (dir);
  while ((dp = readdir (dir)) != NULL) {
   files[i] = strdup (dp->d_name);
   if (files[i] == NULL) {
      /* memory allocation failure; free what's been allocated
       * so far and return NULL.*/
      while (i > 0) free (files[--i]);

      free (files);
      return NULL;
    }
    i++;
  }

  closedir (dir);
  return files;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
char *extractElement(char *lines, int position) {

  if (position < 1) return NULL;
  char *pch = strtok (lines,", \n");
  if (position == 1) return pch;
  int intPos = 1;
  while (pch != NULL) {
    pch = strtok (NULL, ", \n");
    if (++intPos == position) return pch;
  }
  return NULL;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
char* splitPosLine(char *line, int pos, char character) {

  if (pos < 0) return NULL;

  int   count = 1, length = 0;
  char *tmpResult = new char[strlen(line) + 1];

  for (int i = 0; i < strlen(line); i++) {
    if (line[i] == character) { count++; i++; }
    if (pos == count) tmpResult[length++] = line[i];
  }
  tmpResult[length] = '\0';

  char *result = new char[length + 1];
  strcpy(result, tmpResult);
  result[length] = '\0';
  delete[] tmpResult;

  return result;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void changeBondCharacter(char **molecule) {

  if (!molecule || !*molecule ) return;
  for (int i = 0; i < strlen(*molecule); i++)
    if (isdigit((*molecule)[i]))
      (*molecule)[i] = CHANGEDIGIT;


}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int numberRepetition(char *sequence, char *lingo) {

  if (!sequence || !lingo) return -1;

  int   count = 0;
  char *tmpSeq = sequence;
  changeBondCharacter(&tmpSeq);
  while ((tmpSeq = strstr(tmpSeq, lingo)) != NULL) {
    tmpSeq = tmpSeq + 1; count++;
  }

  return count;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int main(int argc, char *argv[]) {

  char  *nameCluFile = NULL, *nameSeqFile = NULL, *nameOutFile = NULL;

  if   (argc < 4) return 0;
  else {
    nameCluFile = new char[strlen(argv[1]) + 1];
    strcpy(nameCluFile, argv[1]);
    nameSeqFile = new char[strlen(argv[2]) + 1];
    strcpy(nameSeqFile, argv[2]);
    nameOutFile = new char[strlen(argv[3]) + 1];
    strcpy(nameOutFile, argv[3]);
  }

  //Read the configuration File
  if (!nameCluFile || !nameSeqFile || !nameOutFile) {
    if (nameCluFile)   delete[] nameCluFile;
    if (nameSeqFile)   delete[] nameSeqFile;
    if (nameOutFile)   delete[] nameOutFile;
    return 0;
  }

  TListE *listSmiles  = new TListE;
  gzFile  sequenceFile = gzopen(nameSeqFile, "rb9");
  char   *buffer      = new char[LENGTHARRAY + 1];
  int     count       = 0;

  printf("Open the Library file %s\n", nameSeqFile);

  while (!gzeof(sequenceFile)) {
    gzgets(sequenceFile, buffer, LENGTHARRAY);
    char *smilesTmp = splitPosLine(buffer, 1, ','); trim(smilesTmp);
    char *refTmp    = splitPosLine(buffer, 2, ','); trim(refTmp);
    printf("[%d]smilesTmp %s, refTmp %s\n", ++count, smilesTmp, refTmp);
    SMILESRef *lingoFreqEle = new SMILESRef;
    lingoFreqEle->smiles = smilesTmp;
    lingoFreqEle->ref    = refTmp;
    listSmiles->Add(lingoFreqEle);
  }

  gzclose(sequenceFile);

  printf("Analize the sequences with the Library\n");

  gzFile clusterFile = gzopen(nameCluFile,   "rb9");
  gzFile outFile     = gzopen(nameOutFile,   "wb9");

  while (!gzeof(clusterFile)) {

    gzgets(clusterFile, buffer, LENGTHARRAY);
    char *tmpRef = splitPosLine(buffer, 1, ' '); trim(tmpRef);

    SMILESRef *tmpSmilesRef = (SMILESRef*)listSmiles->FirstOcurrence(LingoSpace::FindReference, tmpRef);

    if (tmpRef) delete[] tmpRef;
    if (!tmpSmilesRef) continue;

    gzprintf(outFile, "%s, %s\n\0", tmpSmilesRef->smiles, tmpSmilesRef->ref);

    printf("%s, %s\n\0", tmpSmilesRef->smiles, tmpSmilesRef->ref);

  }

  gzclose(outFile);
  gzclose(clusterFile);

  if (listSmiles)    delete   listSmiles;
  if (nameCluFile)   delete[] nameCluFile;
  if (nameSeqFile)   delete[] nameSeqFile;
  if (nameOutFile)   delete[] nameOutFile;
  if (buffer)        delete[] buffer;

  return 1;

}


